<?php

namespace app\models\tableModel;

use app\entity\PageListEntity;
use app\models\tableModel\base\FileUploadRecord;
use \app\models\cacheModel\SettingModel as SettingCacheModel;
use app\service\tool\UtilsService;
use app\service\UploadFileService;
use yii\db\Expression;
use yii\db\ExpressionInterface;
use yii\helpers\ArrayHelper;

/**
 * [文件上传记录]操作模型
 * 作者: Editor Name
 * 日期: 2021/09/14
 * 时间: 11:22:13
 */
class FileUploadRecordModel extends FileUploadRecord
{

    /**
     * 状态 列表
     * @var array
     */
    private static $statusList = [
        [
            'key'   => 'delete',
            'value' => -1,
            'text'  => '已删除'
        ],
        [
            'key'   => 'normal',
            'value' => 0,
            'text'  => '未使用'
        ],
        [
            'key'   => 'used',
            'value' => 1,
            'text'  => '已使用'
        ]
    ];
    /**
     * 场景 列表
     * @var array
     */
    private static $scenarioList = [
        [
            'key'   => 'setting',
            'value' => 1,
            'text'  => '设置图片',
            'type'  => UploadFileService::imageType
        ],
        [
            'key'   => 'user',
            'value' => 2,
            'text'  => '用户头像',
            'type'  => UploadFileService::imageType
        ],
        [
            'key'   => 'news_category',
            'value' => 3,
            'text'  => '文章分类图片',
            'type'  => UploadFileService::imageType
        ],
        [
            'key'   => 'news',
            'value' => 4,
            'text'  => '文章图片',
            'type'  => UploadFileService::imageType
        ],
        [
            'key'   => 'block',
            'value' => 5,
            'text'  => '页面碎片',
            'type'  => UploadFileService::imageType
        ]
    ];
    /**
     * 是否管理员操作记录 列表
     * @var array
     */
    private static $isAdminList = [
        [
            'key'   => 'yes',
            'value' => 1,
            'text'  => '是'
        ],
        [
            'key'   => 'no',
            'value' => -1,
            'text'  => '否'
        ]
    ];

    /**
     * 规则验证
     * @return array
     */
    public function rules()
    {

        // [状态]列表
        $statusList = array_column(self::getStatusList(), 'value');
        // [场景]列表
        $scenarioList = array_column(self::getScenarioList(), 'value');
        // [是否管理员操作记录]列表
        $isAdminList = array_column(self::getIsAdminList(), 'value');

        $parent = parent::rules();
        return ArrayHelper::merge($parent, [
            ['status', 'in', 'range' => $statusList, 'message' => '状态不合法'],
            ['scenario', 'in', 'range' => $scenarioList, 'message' => '场景不合法'],
            ['is_admin', 'in', 'range' => $isAdminList, 'message' => '是否管理员操作记录不合法'],
        ]);
    }

    /**
     * 重写label的 文字
     */
    public function attributeLabels()
    {

        $parent = parent::attributeLabels();
        return array_merge($parent, [
            'id'               => '编号',
            'name'             => '本地保存的文件名称',
            'path'             => '本地保存的文件路径',
            'third_return_url' => '第三方上传链接返回',
            'status'           => '状态',
            'type'             => '类型',
            'file_type'        => '文件类型',
            'uid'              => '用户编号',
            'add_time'         => '时间',
            'update_time'      => '更新时间',
        ]);
    }

    /**
     * 场景
     * @return array
     */
    public function scenarios()
    {

        $scenarios = parent::scenarios();
        return ArrayHelper::merge($scenarios, [
            // 自定义场景 (无用请删除)
            'scUpdate' => [
                'someAttributes'
            ]
        ]);
    }

    /**
     * 自定义过滤单条[where]
     *  ` 仅限于通过方法[loadWhere]传入的条件, 可以在其中自定义逻辑
     *  ` 保证最终返回值为一维数组[Yii2]通用条件格式[运算符, 字段名, 值]
     * @param $condition array [sql]查询条件, 严格遵循Yii多条件查询:[运算符, 字段名, 值]
     * @return array
     */
    public function whereCustomFilter($condition = [])
    {

        // // 例：字段为编号 —— 操作符使用[IN]
        // if ($field == 'id') {
        //     return ['IN', $condition[1], $value[2]];
        // }

        // 最终返回必须为数组：[运算符, 字段名, 值]，符合Yii2规范
        return $condition;
    }

    /**
     * 获取分页信息
     * @param integer $page 当前页
     * @param integer $limit 获取几条
     * @param null $field 获取字段
     * @return PageListEntity
     */
    public function getPaginate($page, $limit, $field = null)
    {

        // 当前页面计算
        $page = max($page - 1, 0);

        // 查找的 字段空的 就默认给列表
        if (!$field) $field = '*';

        // 基础 where加载完毕
        $this->getBaseSql()->select($field);

        // 是否已经有自定义排序
        if (property_exists($this, 'orderBy') && !empty($this->orderBy)) {
            $this->getBaseSql()->orderBy($this->orderBy);
        } else { // 无自定义排序
            $this->getBaseSql()->orderBy('id desc');
        }

        // 数据的获取 分页等
        $list = $this->getBaseSql()->offset($page * $limit)
            ->limit($limit)
            ->asArray()->all();
        // 总数量
        $total = $this->getBaseSql()->count();

        // 格式化数据
        foreach ($list as $k => &$v) {

            // 更新时间
            if (isset($v['add_time'])) {
                $v['add_time_text']   = date('Y-m-d H:i:s', $v['add_time']);
                $v['add_time_text_s'] = date('Y-m-d', $v['add_time']);
            }

            // 更新时间
            if (isset($v['update_time'])) {
                $v['update_time_text']   = date('Y-m-d H:i:s', $v['update_time']);
                $v['update_time_text_s'] = date('Y-m-d', $v['update_time']);
            }

            // 状态 文本
            if (isset($v['status'])) {
                $v['status_text'] = self::getStatusText($v['status']);
            }
        }

        return PageListEntity::loadModel(compact('list', 'total'));
    }

    /**
     * 添加|保存
     * @param bool $runValidation 是否仅仅运行验证，不运行保存
     * @param string[]|null|string $attributeNames 仅仅保存某几个字段
     * @return bool
     */
    public function save($runValidation = false, $attributeNames = null)
    {

        $nowTime = time();
        // 添加的话要赋值一些初始数据
        if (empty($this->id)) {

            // 添加时间
            $this->add_time = $nowTime;
        }

        // 更新时间
        $this->update_time = $nowTime;
        // 检测
        if ($this->hasErrors() || !$this->validate($attributeNames)) {

            // 记录下错误日志
            \Yii::error([
                "`````````````````````````````````````````````````````````",
                "``                      数据库错误                       ``",
                "`` 错误详情: [[文件上传记录]操作模型]验证数据失败             ``",
                "`` 错误信息和参数详情:                                     ``",
                "`````````````````````````````````````````````````````````",
                $this->getErrors()
            ], 'db');
            return false;
        }

        // 需要 && 执行保存
        if (!$runValidation && !parent::save(false, $attributeNames)) {

            // 记录下错误日志
            \Yii::error([
                "`````````````````````````````````````````````````````````",
                "``                      数据库错误                       ``",
                "`` 错误详情: [[文件上传记录]操作模型]保存数据失败             ``",
                "`` 错误信息和参数详情:                                     ``",
                "`````````````````````````````````````````````````````````",
                $this->getErrors()
            ], 'db');
            return false;
        }

        return true;
    }

    /**
     * [静态方法]批量快速更新某些字段
     * @param $condition
     * @param array $fieldVal
     * @return bool
     */
    public static function updateField($condition, $fieldVal = [])
    {

        // 验证字段
        $model = self::loadModel();
        $model->load($fieldVal, '');
        if (!$model->validate(array_keys($fieldVal))) {
            $error = UtilsService::getModelError($model->getErrors());
            self::$error_[$error['column']] = [$error['msg']];
            return false;
        }
        // 重新取值规则化后的特定值列表
        $fieldVal = $model->getAttributes(array_keys($fieldVal));

        $db = \Yii::$app->db->createCommand();

        try {

            $db->update(self::tableName(), $fieldVal, $condition)->execute();

            // 否则成功
            return true;
        } catch (\Exception $error) {

            // 记录下错误日志
            \Yii::error([
                "`````````````````````````````````````````````````````````",
                "``                      数据库错误                       ``",
                "`` 错误详情: [[文件上传记录]操作模型]批量修改[指定字段]失败，   ``",
                "``         {$error->getMessage()}                       ``",
                "`` SQL语句: {$db->getRawSql()}                         ``",
                "`` 错误信息和参数详情:                                     ``",
                "`````````````````````````````````````````````````````````",
                $error->getTraceAsString()
            ], 'db');

            // 静态错误
            self::$error_['db_error'] = empty(self::$error_['db_error']) ?
                [$error->getMessage()] : array_merge(self::$error_['db_error'], [$error->getMessage()]);

            return false;
        }
    }

    /**
     * 批量添加数据
     * @param array $createData
     * @return bool
     */
    public static function createData($createData = [])
    {

        $db = \Yii::$app->db->createCommand();
        try {

            ### 先数据格式化
            // 如果是一维数组则二维数组化
            if (ArrayHelper::isAssociative($createData)) {
                $createData = [$createData];
            }
            $values = [];
            foreach ($createData as $k => $v) {

                $model = self::loadModel();
                $model->load($createData[$k], '');
                if (!$model->save(true)) {
                    // 取出错误信息
                    $error = UtilsService::getModelError($model->errors);
                    // 添加到静态方法上
                    self::$error_[$error['column']] = [$error['msg']];
                    return false;
                }

                $createData[$k] = $model->getAttributes($model::getTableSchema()->getColumnNames());

                // 循环一些数据
                foreach ($createData[$k] as $kc => $vc) {
                    // 字段类型为[JSON]类型需要转为[JSON]
                    if (is_array($vc)) {
                        $createData[$k][$kc] = json_encode($vc, JSON_UNESCAPED_UNICODE);
                        continue;
                    }
                }

                // 值赋值
                $values[] = array_values($createData[$k]);;
            }

            ### 取出此次操作的字段列表
            $columns = !current($createData) ? [] : array_keys(current($createData));

            // 执行
            $addResult = $db->batchInsert(self::tableName(), $columns, $values)->execute();

            return $addResult;
        } catch (\Exception $error) {

            // 记录下错误日志
            \Yii::error([

                "`````````````````````````````````````````````````````````",
                "``                      数据库错误                       ``",
                "`` 错误详情: [[文件上传记录]操作模型]批量添加[数据]失败，      ``",
                "``         {$error->getMessage()}                       ``",
                "`` SQL语句: {$db->getRawSql()}                         ``",
                "`` 错误信息和参数详情:                                     ``",
                "`````````````````````````````````````````````````````````",
                $error->getTraceAsString()
            ], 'db');

            // 静态错误
            self::$error_['db_error'] = empty(self::$error_['db_error']) ?
                [$error->getMessage()] : array_merge(self::$error_['db_error'], [$error->getMessage()]);

            return false;
        }
    }

    /**
     * 更新某些字段自增|自减
     * @param $condition
     * @param array $fieldVal 增/减加的字段
     * @return bool
     */
    public static function updateCounter($condition, $fieldVal = [])
    {

        $model = new self();
        foreach ($fieldVal as $k => $v) {

            if (!$model->hasAttribute($k)) {

                unset($fieldVal[$k]);
                continue;
            }
        }

        try {

            $model->updateAllCounters($fieldVal, $condition);

            // 否则成功
            return true;
        } catch (\Exception $error) {

            // 记录下错误日志
            \Yii::error([

                "`````````````````````````````````````````````````````````",
                "``                      数据库错误                       ``",
                "`` 错误详情: [[文件上传记录]操作模型]批量增/减[指定字段]失败   ``",
                "``         {$error->getMessage()}                       ``",
                "`` 错误信息和参数详情:                                     ``",
                "`````````````````````````````````````````````````````````",
                $error->getTraceAsString()
            ], 'db');

            // 静态错误
            self::$error_['db_error'] = empty(self::$error_['db_error']) ?
                [$error->getMessage()] : array_merge(self::$error_['db_error'], [$error->getMessage()]);

            return false;
        }
    }


    /**
     * 获取[状态][已使用]值
     * @return mixed
     */
    public static function getStatusUsed()
    {

        $list = array_column(self::$statusList, null, 'key');
        return $list['used']['value'];
    }

    /**
     * 获取[状态][删除]值
     * @return mixed
     */
    public static function getStatusDelete()
    {

        $list = array_column(self::$statusList, null, 'key');
        return $list['delete']['value'];
    }

    /**
     * 获取[状态][未使用]值
     * @return mixed
     */
    public static function getStatusNormal()
    {

        $list = array_column(self::$statusList, null, 'key');
        return $list['normal']['value'];
    }

    /**
     * 获取[状态]文本
     * @param $value
     * @return mixed|string
     */
    public static function getStatusText($value)
    {

        // 列表
        $list = array_column(self::$statusList, null, 'value');
        // 不合法 - 不存在
        if (empty($list[$value]['text']))

            return '--';

        // 最终正常返回
        return $list[$value]['text'];
    }

    /**
     * 获取[状态]列表 值
     * @return mixed|string
     */
    public static function getStatusList()
    {

        // 最终正常返回
        return self::$statusList;
    }

    /**
     * 根据键获取类型
     * @param $value
     * @return mixed|string
     */
    public static function getScenarioVal($value)
    {
        // 列表
        $list = self::$scenarioList;
        // 不合法 - 不存在
        if (!isset($list[$value]['value'])) return 0;

        // 最终正常返回
        return $list[$value]['value'];
    }

    /**
     * 获取[类型]文本
     * @param $value
     * @return mixed|string
     */
    public static function getScenarioText($value)
    {

        // 列表
        $list = array_column(self::$scenarioList, null, 'value');
        // 不合法 - 不存在
        if (empty($list[$value]['text'])) return '--';

        // 最终正常返回
        return $list[$value]['text'];
    }

    /**
     * 获取[场景]type
     * @param $scenario
     * @return null
     */
    public static function getScenarioListType($scenario)
    {
        $scenarioList = array_column(self::$scenarioList, null, 'key');
        $value        = empty($scenarioList[$scenario]) ? null : $scenarioList[$scenario];
        return empty($value['type']) ? null : $value['type'];
    }

    /**
     * 获取[场景]key
     * @param $scenario
     * @return null
     */
    public static function getScenarioListKey($scenario)
    {
        $scenarioList = array_column(self::$scenarioList, null, 'key');
        $value        = empty($scenarioList[$scenario]) ? null : $scenarioList[$scenario];
        return empty($value['key']) ? null : $value['key'];
    }

    /**
     * 获取[类型]列表 值
     * @return mixed|string
     */
    public static function getScenarioList()
    {

        // 最终正常返回
        return self::$scenarioList;
    }

    /**
     * 获取[场景]type
     * @param $scenario
     * @return null
     */
    public static function getScenarioType($scenario)
    {
        $scenarioList = array_column(self::$scenarioList, null, 'key');
        $value = empty($scenarioList[$scenario]) ? null : $scenarioList[$scenario];
        return empty($value['type']) ? null : $value['type'];
    }

    /**
     * 获取[场景]key
     * @param string $scenario 场景
     * @param bool $getFolderPath 是否塑造为文件夹
     * @return null
     */
    public static function getScenarioKey($scenario, $getFolderPath = false)
    {
        $scenarioList = array_column(self::$scenarioList, null, 'key');
        $value        = empty($scenarioList[$scenario]) ? null : $scenarioList[$scenario];
        $key = empty($value['key']) ? null : $value['key'];

        // 无需分割驼峰字符
        if (!$getFolderPath) return $key;

        // 将 _ 替换为 -
        $key = str_replace('_', '-', $key);
        // 根据大写字母分割为数组
        $key = UtilsService::splitUpperCase($key);

        return $key;
    }


    /**
     * 获取[是否管理员操作记录][是]值
     * @return mixed
     */
    public static function getIsAdminYes()
    {

        $list = array_column(self::$isAdminList, null, 'key');
        return $list['yes']['value'];
    }

    /**
     * 获取[是否管理员操作记录][不是]值
     * @return mixed
     */
    public static function getIsAdminNo()
    {

        $list = array_column(self::$isAdminList, null, 'key');
        return $list['no']['value'];
    }

    /**
     * 获取[是否管理员操作记录]文本
     * @param $value
     * @return mixed|string
     */
    public static function getIsAdminText($value)
    {

        // 列表
        $list = array_column(self::$isAdminList, null, 'value');
        // 不合法 - 不存在
        if (empty($list[$value]['text']))

            return '--';

        // 最终正常返回
        return $list[$value]['text'];
    }

    /**
     * 获取[是否管理员操作记录]列表 值
     * @return mixed|string
     */
    public static function getIsAdminList()
    {

        // 最终正常返回
        return self::$isAdminList;
    }


    /**
     * 是否开启第三方云上传
     * @return bool
     */
    public static function isYunStorage()
    {
        return SettingCacheModel::getSetting('upload_type') == 2;
    }

    /**
     * 获取静态错误
     * @return mixed
     */
    public static function getStaticErrors()
    {
        return self::$error_;
    }
}
